#    Copyright 2012 New Mexico EPSCoR
#
#    This file is part of Teacher's P.E.T.
#
#    Teacher's P.E.T. is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Teacher's P.E.T. is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Teacher's P.E.T..  If not, see <http://www.gnu.org/licenses/>.
from models import *
from django.forms.models import modelformset_factory
from collections import defaultdict

import random
import re

# Create your views here.
def CreateActivityFormset(activity = None, postinfo = None, course=None):
    QuestionForms = []
    ActivityForm = ActivityEditForm(postinfo, instance=activity, course=course)
    if activity:
        for section in activity.questions.order_by('section_number'):
            QuestionForm = ActivityQuestionForm(postinfo,instance=section,prefix="section%s"%(section.section_number))
            ResponseList = []
            for response in ActivityAutogradeResponse.objects.filter(question=section):
                ResponseList.append(ActivityAutogradeResponseForm(postinfo,instance=response,prefix="section%s_response%s"%(section.section_number, response.id)))
            QuestionForms.append((QuestionForm,ResponseList))
    return ActivityForm,QuestionForms

def CreateActivityResponseSet(activity, question_id=None, user=None):
    Questions = activity.questions.order_by('section_number')
    if question_id: Questions = Questions.filter(section_number=question_id)
    Responses = {}
    for question in Questions:
        Responses[question] = []
        Responses[question].extend(ActivityResponseBoolean.objects.filter(section=question, user=user) if user else ActivityResponseBoolean.objects.filter(section=question))
        Responses[question].extend(ActivityResponseShortAnswer.objects.filter(section=question, user=user) if user else ActivityResponseShortAnswer.objects.filter(section=question))
        Responses[question].extend(ActivityResponseLongAnswer.objects.filter(section=question, user=user) if user else ActivityResponseLongAnswer.objects.filter(section=question))
        Responses[question].extend(ActivityResponseInteger.objects.filter(section=question, user=user) if user else ActivityResponseInteger.objects.filter(section=question))
        Responses[question].extend(ActivityResponseFloat.objects.filter(section=question, user=user) if user else ActivityResponseFloat.objects.filter(section=question))
        Responses[question].extend(ActivityResponseMultipleChoice.objects.filter(section=question, user=user) if user else ActivityResponseMultipleChoice.objects.filter(section=question))
        Responses[question].extend(ActivityResponseFileUpload.objects.filter(section=question, user=user) if user else ActivityResponseFileUpload.objects.filter(section=question))
        if not Responses[question]: del Responses[question]
    return Responses

def CreateActivityResponseFormset(course, activity, user, id=None, postinfo = None, files = None):
    QuestionFormDict = {'Questions':ActivityResponseFormsetContainer()}
    Questions = activity.questions.order_by('section_number')
    if id: Questions = Questions.filter(section_number=id)
    section_indices = range(0,len(Questions))
    if activity.randomize_questions: random.shuffle(section_indices)
    for index,question in enumerate(Questions):
        section = question.gradingsection_ptr
        if question.type == "BOOL-TF" or question.type == "BOOL-YN":
            item = ActivityResponseBoolean.objects.filter(section=question,user=user)
        elif question.type == "CHAR":
            item = ActivityResponseShortAnswer.objects.filter(section=section,user=user)
        elif question.type == "TEXT":
            item = ActivityResponseLongAnswer.objects.filter(section=section,user=user)
        elif question.type == "INT":
            item = ActivityResponseInteger.objects.filter(section=section,user=user)
        elif question.type == "FLOAT":
            item = ActivityResponseFloat.objects.filter(section=section,user=user)
        elif question.type == "CHOICE-RADIO" or question.type == "CHOICE-BOX":
            item = ActivityResponseMultipleChoice.objects.filter(section=section,user=user)
        elif question.type == "UPLOAD":
            item = ActivityResponseFileUpload.objects.filter(section=section,user=user)
        if item: item = item[0]
        else:
            if question.type == "BOOL-TF" or question.type == "BOOL-YN":
                item = ActivityResponseBoolean(section=section,user=user)
            elif question.type == "CHAR":
                item = ActivityResponseShortAnswer(section=section,user=user)
            elif question.type == "TEXT":
                item = ActivityResponseLongAnswer(section=section,user=user)
            elif question.type == "INT":
                item = ActivityResponseInteger(section=section,user=user)
            elif question.type == "FLOAT":
                item = ActivityResponseFloat(section=section,user=user)
            elif question.type == "CHOICE-RADIO" or question.type == "CHOICE-BOX":
                item = ActivityResponseMultipleChoice(section=section,user=user)
            elif question.type == "UPLOAD":
                item = ActivityResponseFileUpload(section=section,user=user)

        if question.type == "BOOL-TF":
            form = ActivityResponseBooleanTFForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "BOOL-YN":
            form = ActivityResponseBooleanYNForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "CHAR":
            form = ActivityResponseShortAnswerForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "TEXT":
            form = ActivityResponseLongAnswerForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "INT":
            form = ActivityResponseIntegerForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "FLOAT":
            form = ActivityResponseFloatForm(postinfo,instance=item,prefix="question%d"%section.section_number)
        elif question.type == "CHOICE-RADIO":
            form = ActivityResponseMultipleChoiceRadioForm(postinfo,choices=question.get_choices(),instance=item,prefix="question%d"%section.section_number)
        elif question.type == "CHOICE-BOX":
            form = ActivityResponseMultipleChoiceBoxForm(postinfo,choices=question.get_choices(),instance=item,prefix="question%d"%section.section_number)
        elif question.type == "UPLOAD":
            form = ActivityResponseFileUploadForm(postinfo,files,instance=item,prefix="question%d"%section.section_number)
        form_container = ActivityResponseFormContainer(course=course,user=user,activity_question=question,question_number=section_indices[index]+1,activity_response_form=form)
        QuestionFormDict['Question%s'%(section_indices[index]+1)] = form_container
        QuestionFormDict['Questions'].append(form_container)

    QuestionFormDict['Questions'].sort(key=lambda question: question.question_number)
    return QuestionFormDict

def nice_sort(l):
    """ Sort the given iterable in the way that humans expect."""
    convert = lambda text: int(text) if text.isdigit() else text 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key[0]) ] 
    return sorted(l, key = alphanum_key)

def GenerateMetrics(course, activity, user=None, question=None):
    from options import Options
    NO_ANSWER_TEXT = re.sub('\s', '&'+'nbsp;', Options.get_option('Blank Answer Text','** No answer given **'))
    Questions = activity.questions.order_by('section_number')
    if question: Questions = Questions.filter(section_number=question)
    Metrics = {}
    CourseUsers = [participant.user for participant in CourseParticipant.objects.filter(course=course,status="STUDENT")]
    for question in Questions:
        if question.type == 'BOOL-TF':
            if not user:
                answers = {'True':0,'False':0,NO_ANSWER_TEXT:len(CourseUsers)}
                for item in ActivityResponseBoolean.objects.filter(section=question):
                    if item.response is not None:
                        answers['True' if item.response else 'False'] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1
                Metrics[question] = nice_sort(answers.items())
            else:
                answer = ActivityResponseBoolean.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        if question.type == 'BOOL-YN':
            if not user:
                answers = {'Yes':0,'No':0,NO_ANSWER_TEXT:len(CourseUsers)}
                for item in ActivityResponseBoolean.objects.filter(section=question):
                    if item.response is not None:
                        answers['Yes' if item.response else 'No'] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1
                Metrics[question] = nice_sort(answers.items())
            else:
                answer = ActivityResponseBoolean.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'CHAR':
            if not user:
                answers = defaultdict(int); answers[NO_ANSWER_TEXT] = len(CourseUsers)
                for item in ActivityResponseShortAnswer.objects.filter(section=question):
                    if item.response is not None:
                        answers[item.response] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseShortAnswer.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'TEXT':
            if not user:
                answers = defaultdict(int); answers['Not Responded'] = len(CourseUsers)
                for item in ActivityResponseLongAnswer.objects.filter(section=question):
                    if item.response is not None:
                        answers['Responded'] += 1;
                        if item.user in CourseUsers: answers['Not Responded'] -= 1
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseLongAnswer.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'INT':
            if not user:
                answers = defaultdict(int); answers[NO_ANSWER_TEXT] = len(CourseUsers)
                for item in ActivityResponseInteger.objects.filter(section=question):
                    if item.response is not None:
                        answers[str(item.response)] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseInteger.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'FLOAT':
            if not user:
                answers = defaultdict(int); answers[NO_ANSWER_TEXT] = len(CourseUsers)
                for item in ActivityResponseFloat.objects.filter(section=question):
                    if item.response is not None:
                        answers[str(item.response)] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseFloat.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'UPLOAD':
            if not user:
                answers = defaultdict(int); answers['Not Submitted'] = len(CourseUsers)
                for item in ActivityResponseFileUpload.objects.filter(section=question):
                    if item.response is not None:
                        answers['Submitted'] += 1;
                        if item.user in CourseUsers: answers['Not Submitted'] -= 1
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseFileUpload.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
        elif question.type == 'CHOICE-RADIO' or question.type == 'CHOICE-BOX':
            if not user:
                choices = [item.strip() for item in question.choices.split(';')] + [NO_ANSWER_TEXT]
                answers = dict(zip(choices,[0]*len(choices))); answers[NO_ANSWER_TEXT] = len(CourseUsers)
                for item in ActivityResponseMultipleChoice.objects.filter(section=question):
                    if item.response is not None:
                        answers[choices[int(item.response)]] += 1;
                        if item.user in CourseUsers: answers[NO_ANSWER_TEXT] -= 1;
                Metrics[question] = nice_sort(answers.items()) if answers else ['No answers have been given yet']
            else:
                answer = ActivityResponseMultipleChoice.objects.filter(section=question,user=user)
                if answer: Metrics[question] = answer[0]
                else: Metrics[question] = None
    return Metrics

def Autograde(poll):
    pass
    #Questions = poll.questions.order_by('section_number')
    #PollsCompleted = PollCompleted.objects.filter(poll=poll)
    #PollsCompleted = dict(zip([item.user for item in PollsCompleted],PollsCompleted))
    #
    #for user,poll_completed in PollsCompleted.items():
    #    poll_completed.points = 0.0
    #for question in Questions:
    #    if type(question).__name__ == "GradingSection": continue
    #    items = {
    #        'BOOL-TF': BooleanPollAnswer.objects.filter(poll_question=question),
    #        'BOOL-YN': BooleanPollAnswer.objects.filter(poll_question=question),
    #        'CHAR': CharPollAnswer.objects.filter(poll_question=question),
    #        'TEXT': TextPollAnswer.objects.filter(poll_question=question),
    #        'INT': IntPollAnswer.objects.filter(poll_question=question),
    #        'FLOAT': FloatPollAnswer.objects.filter(poll_question=question),
    #        'CHOICE': ChoicePollAnswer.objects.filter(poll_question=question),
    #      }[question.type]
    #    for item in items:
    #        poll_completed = PollsCompleted[item.user]
    #        answer = item.value
    #        if question.type == 'CHOICE':
    #            answer = question.choices.split(';')[int(item.value)].strip()
    #        for response in PollResponse.objects.filter(poll_question=item.poll_question):
    #            if str(answer).lower() == str(response.response).lower() and item.points != response.points:
    #                item.points = response.points
    #                item.notes = response.notes
    #                item.save()
    #                if poll_completed: poll_completed.is_autograde = True
    #        if poll_completed: poll_completed.points += item.points
    #for user,poll_completed in PollsCompleted.items():
    #    poll_completed.save()